package scheduler

import (
	"crawler_distributied/engine"
)

// 队列调度器
type QueuedScheduler struct {
	// 定义 Request 队列
	requestChan chan engine.Request
	// 定义 Worker 队列
	workerChan chan chan engine.Request
}

// queuedScheduler 中每一个 Request 都会创建一个 channel
func (s *QueuedScheduler) WorkerChan() chan engine.Request {
	return make(chan engine.Request)
}

// 提交请求到 requestChan
func (s *QueuedScheduler) Submit(r engine.Request) {
	s.requestChan <- r
}

// 告诉外界有一个 worker 可以接收 request
func (s *QueuedScheduler) WorkerReady(w chan engine.Request) {
	s.workerChan <- w
}

// 队列调度
func (s *QueuedScheduler) Run() {
	// 定义 requestChan 和 workerChan
	s.requestChan = make(chan engine.Request)
	s.workerChan = make(chan chan engine.Request)

	go func() {
		// 创建队列, 把收到的 Request 和 worker 分别放在队列中进行排队
		var requestQ []engine.Request
		var workerQ []chan engine.Request
		for {
			// 什么时候可以把 Request 发送给 Worker ??
			// 当 requestQ 队列和 workerQ 队列同时有数据时, 即 Request 和 worker 同时都有在排队时

			var activeRequest engine.Request
			var activeWorker chan engine.Request
			if len(requestQ) > 0 && len(workerQ) > 0 {
				// 从队列中取出第一个数据, 但此时还不能直接取出来第一个数据, 只是作了一个标记
				// 当在 select 中真正能够把 request 放入到 worker 中之后, 才从队列中删除数据
				activeRequest = requestQ[0]
				activeWorker = workerQ[0]
			}

			// 所有对 chan 的操作都放在 select 中执行
			select {
			case r := <-s.requestChan: // requestChan 收到数据
				requestQ = append(requestQ, r)
			case w := <-s.workerChan: // workerChan 收到数据
				workerQ = append(workerQ, w)
			case activeWorker <- activeRequest: // 当请求队列有数据和worker队列有空闲时
				requestQ = requestQ[1:]
				workerQ = workerQ[1:]
				//fmt.Printf("requestQ: %d, workerQ: %d\n", len(requestQ), len(workerQ))
			}
		}
	}()
}
